<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>sendbeacon | 一枚前端小菜鸟的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="分享主题： 接口超时设置、监控日志上报方式 sendBeacon 一、接口交互方式1.1、XMLHttpRequestXMLHttpRequest 原生的接口交互方式 1.2、AjaxAjax 基于 XMLHttpRequest（XHR） 浏览器和服务器之间的异步数据传输技术 1.3、AxiosAxios 基于 Promise，用于浏览器和 node.js 的 http 客户端  支持 Promi">
<meta property="og:type" content="article">
<meta property="og:title" content="sendbeacon">
<meta property="og:url" content="https://gitee.com/weiyayun1995/weiyayun1995.git/2021/06/18/sendbeacon/index.html">
<meta property="og:site_name" content="一枚前端小菜鸟的博客">
<meta property="og:description" content="分享主题： 接口超时设置、监控日志上报方式 sendBeacon 一、接口交互方式1.1、XMLHttpRequestXMLHttpRequest 原生的接口交互方式 1.2、AjaxAjax 基于 XMLHttpRequest（XHR） 浏览器和服务器之间的异步数据传输技术 1.3、AxiosAxios 基于 Promise，用于浏览器和 node.js 的 http 客户端  支持 Promi">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fe.che300.com/easymock/upload/2020/06/18/a484bf160f147453940df248f9a2cff9.png">
<meta property="article:published_time" content="2021-06-18T06:19:33.000Z">
<meta property="article:modified_time" content="2021-06-18T06:20:22.877Z">
<meta property="article:author" content="yywei">
<meta property="article:tag" content="菜鸟,前端,js,react,vue">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fe.che300.com/easymock/upload/2020/06/18/a484bf160f147453940df248f9a2cff9.png">
  
    <link rel="alternate" href="/atom.xml" title="一枚前端小菜鸟的博客" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/css/style.css">

  
    
<link rel="stylesheet" href="/fancybox/jquery.fancybox.min.css">

  
<meta name="generator" content="Hexo 5.4.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">一枚前端小菜鸟的博客</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/" id="subtitle">yywei的遇坑记录</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS 订阅"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="搜索"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="搜索"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="https://gitee.com/weiyayun1995/weiyayun1995.git"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-sendbeacon" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/2021/06/18/sendbeacon/" class="article-date">
  <time class="dt-published" datetime="2021-06-18T06:19:33.000Z" itemprop="datePublished">2021-06-18</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="p-name article-title" itemprop="headline name">
      sendbeacon
    </h1>
  

      </header>
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <p>分享主题： <code>接口超时设置</code>、监控日志上报方式 <code>sendBeacon</code></p>
<h2 id="一、接口交互方式"><a href="#一、接口交互方式" class="headerlink" title="一、接口交互方式"></a>一、接口交互方式</h2><h3 id="1-1、XMLHttpRequest"><a href="#1-1、XMLHttpRequest" class="headerlink" title="1.1、XMLHttpRequest"></a>1.1、XMLHttpRequest</h3><p><code>XMLHttpRequest</code> 原生的接口交互方式</p>
<h3 id="1-2、Ajax"><a href="#1-2、Ajax" class="headerlink" title="1.2、Ajax"></a>1.2、Ajax</h3><p><code>Ajax</code> 基于 <code>XMLHttpRequest（XHR）</code> 浏览器和服务器之间的异步数据传输技术</p>
<h3 id="1-3、Axios"><a href="#1-3、Axios" class="headerlink" title="1.3、Axios"></a>1.3、Axios</h3><p><code>Axios</code> 基于 <code>Promise</code>，用于浏览器和 <code>node.js</code> 的 <code>http</code> 客户端</p>
<blockquote>
<p>支持 <code>Promise API</code>；<br>提供了一些并发请求的接口；<br>支持拦截请求和响应；<br>转换请求和响应数据；<br>可以取消请求；<br>自动转换 <code>JSON</code> 数据；<br>客户端支持防止 <code>CSRF</code>；<br>客户端支持防御 <code>XSRF</code>。</p>
</blockquote>
<h3 id="1-4、Fetch"><a href="#1-4、Fetch" class="headerlink" title="1.4、Fetch"></a>1.4、Fetch</h3><p><code>Fetch</code> 基于 <code>Promise</code> 设计的，采用了 <code>Promise</code> 对象。提供了一个 <code>JavaScript</code> 接口，用于访问和操纵 <code>HTTP</code> 管道的部分，例如请求和响应。它还提供了一个全局 <code>fetch()</code> 方法，该方法提供了一种简单，合理的方式来跨网络异步获取资源。<code>fetch</code> 没有采用 <code>XMLHttpRequest</code> 对象，所以针对浏览器兼容性，需要使用 <code>polyfill es6-promise</code>。</p>
<blockquote>
<p><code>Fetch</code> 只针对网络请求报错，对 <code>400</code>、<code>500</code> 当成是成功的请求，因此需要封装处理;<br><code>Fetch</code> 不支持 <code>abort</code>，不支持超时控制，使用 <code>setTimeout</code> 及 <code>Promise.race</code> 实现超时控制。</p>
</blockquote>
<h3 id="1-5、img"><a href="#1-5、img" class="headerlink" title="1.5、img"></a>1.5、img</h3><p><code>img</code>：<code>src</code> 注入接口 <code>url</code></p>
<h3 id="1-6、Beacon"><a href="#1-6、Beacon" class="headerlink" title="1.6、Beacon"></a>1.6、Beacon</h3><blockquote>
<p>监听页面在关闭或者刷新时 <code>beforeunload</code> 或者 页面正在被卸载前<code>unload</code> 触发；<br><code>Beacon API</code> 用于将少量数据通过 <code>post</code> 请求发送到服务器；<br><code>Beacon</code> 是非阻塞请求，不需要响应，包括接口错误时，也不会返回响应信息。</p>
</blockquote>
<p>适用于仅提交信息，且不需要得到响应信息的情况。</p>
<h2 id="二、超时设置"><a href="#二、超时设置" class="headerlink" title="二、超时设置"></a>二、超时设置</h2><p>针对超时设置，<code>XMLHttpRequest</code>、<code>Ajax</code>、<code>Axios</code> 可以添加 <code>timeout</code> 参数，而 <code>Fetch</code> 不支持 <code>abort</code>，要想进行超时设置，可采用 <code>setTimeout</code> 及 <code>Promise.race</code> 实现超时控制。</p>
<h6 id="XMLHttpRequest"><a href="#XMLHttpRequest" class="headerlink" title="XMLHttpRequest"></a>XMLHttpRequest</h6><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> xhr = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line">xhr.timeout = <span class="number">3000</span>; <span class="comment">// 设置xhr请求的超时时间</span></span><br><span class="line">xhr.open(<span class="string">&#x27;post&#x27;</span>, <span class="string">&#x27;http://172.16.0.92/xxx&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">xhr.ontimeout = <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">&#x27;请求超时:&#x27;</span>, e);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h6 id="Ajax"><a href="#Ajax" class="headerlink" title="Ajax"></a>Ajax</h6><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$.ajax(&#123;</span><br><span class="line">    timeout: <span class="number">3000</span>, <span class="comment">// 设置超时时间</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h6 id="Axios"><a href="#Axios" class="headerlink" title="Axios"></a>Axios</h6><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">axios(&#123;</span><br><span class="line">    method: <span class="string">&#x27;post&#x27;</span>,</span><br><span class="line">    url: <span class="string">&#x27;/user/12345&#x27;</span>,</span><br><span class="line">    timeout: <span class="number">3000</span>, <span class="comment">// 设置超时时间</span></span><br><span class="line">    data: &#123;</span><br><span class="line">        firstName: <span class="string">&#x27;Fred&#x27;</span>,</span><br><span class="line">        lastName: <span class="string">&#x27;Flintstone&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h6 id="Fetch"><a href="#Fetch" class="headerlink" title="Fetch"></a>Fetch</h6><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;String&#125;</span> </span>url 接口地址</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param <span class="type">&#123;Object&#125;</span> </span>option 配置参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description </span>fetch 请求封装</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fetchHttp</span>(<span class="params">url, option</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> newOptions = &#123;</span><br><span class="line">        headers: &#123;</span><br><span class="line">            Accept: <span class="string">&#x27;application/json&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;application/json; charset=utf-8&#x27;</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        mode: <span class="string">&#x27;cors&#x27;</span>,</span><br><span class="line">        redirect: <span class="string">&#x27;follow&#x27;</span>,</span><br><span class="line">        referrer: <span class="string">&#x27;no-referrer&#x27;</span>,</span><br><span class="line">        ...option,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> ( [<span class="string">&#x27;POST&#x27;</span>, <span class="string">&#x27;PUT&#x27;</span>, <span class="string">&#x27;DELETE&#x27;</span>].includes(option.method)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!(option.body <span class="keyword">instanceof</span> FormData)) &#123;</span><br><span class="line">            newOptions.body = <span class="built_in">JSON</span>.stringify(newOptions.body);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 添加超时拦截请求</span></span><br><span class="line">    <span class="keyword">let</span> controller = <span class="keyword">new</span> AbortController(),</span><br><span class="line">        signal = controller.signal,</span><br><span class="line">        <span class="comment">// 任务1：超时定时任务</span></span><br><span class="line">        timeoutPromise = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">                    resolve(<span class="keyword">new</span> Response(<span class="string">&#x27;timeout&#x27;</span>, &#123; <span class="attr">status</span>: <span class="number">504</span>, <span class="attr">statusText</span>: <span class="string">&#x27;timeout &#x27;</span> &#125;));</span><br><span class="line">                    controller.abort();</span><br><span class="line">                &#125;, timeout);</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 任务2：接口请求</span></span><br><span class="line">        requestPromise = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            newOptions.signal = signal;</span><br><span class="line">            <span class="keyword">return</span> fetch(url, newOptions)</span><br><span class="line">                .then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;</span><br><span class="line">                    <span class="keyword">if</span> (option.method === <span class="string">&#x27;DELETE&#x27;</span> || response.status === <span class="number">204</span>) &#123;</span><br><span class="line">                        <span class="keyword">return</span> response.text();</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">return</span> response.json();</span><br><span class="line">                &#125;)</span><br><span class="line">                .then(<span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>&#123;</span><br><span class="line">                    <span class="keyword">if</span> (option.callback) &#123;</span><br><span class="line">                        option.callback(res);</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">return</span> res;</span><br><span class="line">                &#125;)</span><br><span class="line">                .catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>&#123;</span><br><span class="line">                    <span class="built_in">console</span>.error(<span class="string">&#x27;监控接口请求出错：&#x27;</span>, error);</span><br><span class="line">                &#125;);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 执行多个任务：等待最快对象完成</span></span><br><span class="line">    <span class="built_in">Promise</span>.race([timeoutPromise(), requestPromise()])</span><br><span class="line">        .then(<span class="function"><span class="params">resp</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(resp);</span><br><span class="line">        &#125;)</span><br><span class="line">        .catch(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">&#x27;请求超时:&#x27;</span>, e);</span><br><span class="line">        &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="三、sendBeacon"><a href="#三、sendBeacon" class="headerlink" title="三、sendBeacon"></a>三、sendBeacon</h2><h3 id="3-1、场景"><a href="#3-1、场景" class="headerlink" title="3.1、场景"></a>3.1、场景</h3><p><a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/sendBeacon">Beacon</a> 接口用于将异步和非阻塞请求发送到服务器。<code>Beacon</code> 请求使用 <code>HTTP</code> 协议中的 <code>POST</code> 方法，请求通常不需要响应。这个请求被保证在，页面的 <code>unload</code> 状态从发起到完成之前被发送。且不会产生请求阻塞，影响页面性能。</p>
<blockquote>
<p>页面埋点，监控日志上报；<br>页面/浏览器窗口在关闭前执行接口异步操作。</p>
</blockquote>
<h3 id="3-2、用法"><a href="#3-2、用法" class="headerlink" title="3.2、用法"></a>3.2、用法</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">navigator.sendBeacon(url, data);</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>url</code>：表示 <code>data</code> 将要被发送到的网络地址；<br><code>data</code>：将要发送的 <code>ArrayBufferView</code> 或 <code>Blob</code>, <code>DOMString</code> 或者 <code>FormData</code> 类型的数据。<br>返回值：当用户代理成功把数据加入传输队列时，<code>sendBeacon()</code> 方法将会返回 <code>true</code>，否则返回 <code>false</code>。</p>
</blockquote>
<h3 id="3-3、支持的类型"><a href="#3-3、支持的类型" class="headerlink" title="3.3、支持的类型"></a>3.3、支持的类型</h3><blockquote>
<p><code>text/plain</code>：发送普通字符串</p>
</blockquote>
<p><code>Beacon</code> 中最常用、默认的形式：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">navigator.sendBeacon(url, <span class="built_in">JSON</span>.stringify(data)); <span class="comment">// await parse.json(ctx.req)</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>application/x-www-form-urlencoded</code>：发送 <code>URLSearchParams</code> 对象</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">navigator.sendBeacon(url, <span class="keyword">new</span> URLSearchParams(data)); <span class="comment">// await parse.form(ctx.req)</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>Bolb</code> 类型： 发送 <code>Bolb</code> 对象</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> blob = <span class="keyword">new</span> Blob([<span class="built_in">JSON</span>.stringify(data), &#123;</span><br><span class="line">    <span class="comment">// type: &#x27;application/json&#x27;,</span></span><br><span class="line">    type: <span class="string">&#x27;application/x-www-form-urlencoded&#x27;</span>,</span><br><span class="line">&#125;]);</span><br><span class="line">navigator.sendBeacon(url, blob);</span><br></pre></td></tr></table></figure>

<blockquote>
<p><code>multipart/form-data</code>：发送 <code>FormData</code> 对象</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> formData = <span class="keyword">new</span> FormData();</span><br><span class="line">formData.append(<span class="string">&#x27;text&#x27;</span>, <span class="string">&#x27;测试&#x27;</span>);</span><br><span class="line">navigator.sendBeacon(origin + <span class="string">&#x27;/api/monitor/captureData&#x27;</span>, data);</span><br></pre></td></tr></table></figure>

<h3 id="3-4、实例"><a href="#3-4、实例" class="headerlink" title="3.4、实例"></a>3.4、实例</h3><p>记录在页面上停留的时间：监听浏览器 <code>beforeunload</code> 或者 <code>unload</code></p>
<blockquote>
<p><code>beforeunload</code>：浏览器窗口关闭或者刷新；<br><code>unload</code>：页面正在被卸载。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">&#x27;beforeunload&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// 测试是否支持 Beacon</span></span><br><span class="line">    <span class="keyword">if</span> (!navigator.sendBeacon) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">        start: <span class="keyword">new</span> <span class="built_in">Date</span>().getTime(),</span><br><span class="line">        end: performance.now(),</span><br><span class="line">        url: <span class="built_in">document</span>.URL</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">const</span> url = <span class="string">&#x27;http://127.0.0.1:7071/api/monitor/demo?appKey=85f353b7c54e0f5f24152e55060f7a71&#x27;</span>;</span><br><span class="line">    navigator.sendBeacon(url, <span class="built_in">JSON</span>.stringify(data));</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h3 id="3-5、存在的问题"><a href="#3-5、存在的问题" class="headerlink" title="3.5、存在的问题"></a>3.5、存在的问题</h3><blockquote>
<ol>
<li><code>Beacon</code> 的请求方式统一为 <code>POST</code>，且不支持修改，即使 <code>method</code> 设置成 <code>GET</code> 请求，最终也是以 <code>POST</code> 发送；</li>
<li><code>POST</code> 提交数据，默认 <code>content-type</code> 是 <code>text-plain</code>。在 <code>node + eggjs</code> 服务器中获取不到对应的数据 <code>this.ctx.request.body</code> (拼接在接口地址后面的数据仍然可以使用 <code>this.ctx.request.query</code> 获取)，数据被存储在 <code>this.ctx.req</code> (返回该类型数据 <code>IncomingMessage &#123;&#125;</code>)，通过 <a target="_blank" rel="noopener" href="https://github.com/cojs/co-body">co-body</a> 解析生成需要的字段：</li>
</ol>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> parse = <span class="built_in">require</span>(<span class="string">&#x27;co-body&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> body = <span class="keyword">await</span> parse.json(<span class="built_in">this</span>.ctx.req);</span><br></pre></td></tr></table></figure>

<blockquote>
<p>有网友表示 <code>unload</code> 事件在部分 <code>Mac Safari</code> 上会有安全警告阻止该请求，为保险起见可以在 <code>beforeunload</code> 事件中使用。</p>
</blockquote>
<h3 id="3-6、兼容性"><a href="#3-6、兼容性" class="headerlink" title="3.6、兼容性"></a>3.6、兼容性</h3><p><img src="https://fe.che300.com/easymock/upload/2020/06/18/a484bf160f147453940df248f9a2cff9.png"></p>
<h3 id="3-7、参考网址"><a href="#3-7、参考网址" class="headerlink" title="3.7、参考网址"></a>3.7、参考网址</h3><blockquote>
<p><a target="_blank" rel="noopener" href="https://www.w3.org/TR/beacon/">w3 Beacon</a></p>
</blockquote>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://github.com/cojs/co-body">co-body</a></p>
</blockquote>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/48171879">前端日志上报新姿势 ‘Beacon’</a></p>
</blockquote>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://usefulangle.com/post/63/javascript-navigator-sendbeacon-set-form-http-header">navigator sendbeacon</a></p>
</blockquote>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/weiyayun1995/weiyayun1995.git/2021/06/18/sendbeacon/" data-id="ckq7mlsvd000ddgt9ftpz9auo" data-title="sendbeacon" class="article-share-link">分享</a>
      
      
      
    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2021/06/18/%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">前一篇</strong>
      <div class="article-nav-title">
        
          数字签名
        
      </div>
    </a>
  
  
    <a href="/2021/06/18/js%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%88%A4%E6%96%AD/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">后一篇</strong>
      <div class="article-nav-title">js数据类型的判断</div>
    </a>
  
</nav>

  
</article>


</section>
        
          <aside id="sidebar">
  
    

  
    

  
    
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/06/">六月 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/05/">五月 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/04/">四月 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/03/">三月 2021</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/06/22/js%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8A%E8%BD%AC%E6%8D%A2/">js数据类型及转换</a>
          </li>
        
          <li>
            <a href="/2021/06/18/react-hook-%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%AE%9E%E8%B7%B5/">react-hook 项目中实践</a>
          </li>
        
          <li>
            <a href="/2021/06/18/%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D/">数字签名</a>
          </li>
        
          <li>
            <a href="/2021/06/18/sendbeacon/">sendbeacon</a>
          </li>
        
          <li>
            <a href="/2021/06/18/js%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%88%A4%E6%96%AD/">js数据类型的判断</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      
      &copy; 2021 yywei<br>
      Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="/js/jquery-3.4.1.min.js"></script>



  
<script src="/fancybox/jquery.fancybox.min.js"></script>




<script src="/js/script.js"></script>





  </div>
</body>
</html>